/*
 * @Author: czy
 * @Date: 2021-04-26 22:01:06
 * @LastEditTime: 2021-07-13 15:43:24
 */
#include "string.h"
#include "datetime.h"

#include "sys/container.h"
#include "sys/system.h"
#include "sys/type.h"

#include "../lib/cmd.h"

int cmd(int argc, char *argv[])
{
    Map *cmd = (Map *)(getenv("command"));
    command data;
    memset(&data, '\0', sizeof(data));
    while (cmd->values(cmd, &data) != NULL)
    {
        printk("%s\n", data.name);
    }
}

int help(int argc, char *argv[])
{
    int i = 0;
    if (argc == 1)
    {
        printk("Usage: help [command]\nDisplay info about [command].\n");
    }
    Map *cmd = (Map *)(getenv("command"));
    command *data;
    for (int i = 1; i < argc; i++)
    {
        data = cmd->get(cmd, argv[i]);
        if (data == NULL)
        {
            printk("help: no help topics match `%s`.\n", argv[i]);
        }
        else
        {
            printk("%s\n", data->help_content);
        }
    }
    return i;
}

int history(int argc, char *argv[])
{
    Deque *hisory_cmd = (Deque *)(getenv("history"));
    int num = -1;
    int count = hisory_cmd->length;
    if (argc > 1)
    {
        num = str2int(argv[1]);
    }
    num = num < 0 ? 0 : count - num;
    hisory_cmd->get(hisory_cmd, num);
    for (int i = num; i < count; i++)
    {
        printk("%2d: %s\n", i + 1, hisory_cmd->next(hisory_cmd));
    }
}

int date(int argc, char *argv[])
{
    tm now;
    time_t locale_t;
    gettime(&locale_t);
    localtime(&locale_t, &now);
    char temp[100] = "";
    if (argc == 1)
    {
        strftime(temp, "%a %b\t%H:%M:%S %Y", now);
        printk("%s\n", temp);
    }
    else
    {
        strftime(temp, argv[1], now);
        printk("%s\n", temp);
    }
}

int echo(int argc, char *argv[])
{
    for (int i = 1; i < argc; i++)
    {
        printk("%s ", argv[i]);
    }
    putc('\n');
    return argc - 1;
}

int _sleep(int argc, char *argv[])
{
    if (argc == 1)
    {
        printk("sleep: missing operand\n");
        return 0;
    }
    else
    {
        time_t start, now;
        gettime(&start);
        gettime(&now);
        while (now - start < str2int(argv[1]))
        {
            gettime(&now);
        }
        return str2int(argv[1]);
    }
}

int cal(int argc, char *argv[])
{
    char *month_str[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"};
    tm now;
    time_t locale_t;
    gettime(&locale_t);
    localtime(&locale_t, &now);
    int mday = now.tm_mday;
    if (argc == 2)
    {
        now.tm_mon = str2int(argv[1]) - 1;
    }
    if (argc > 2)
    {
        now.tm_mon = str2int(argv[1]) - 1;
        now.tm_year = str2int(argv[2]);
    }
    now.tm_mday = 1;
    int tol_day = (int)date_difference(base_date(), now);
    int weekday = (tol_day + base_date().tm_wday) % 7;
    int day = month_day(now.tm_mon, now.tm_year);
    printk("      %s %d\n", month_str[now.tm_mon], now.tm_year);
    printk("Su Mo Tu We Th Fr Sa\n");
    now.tm_mday = mday;
    for (int i = 0; i < weekday; i++)
    {
        printk("   ");
    }
    for (int i = 1; i <= day; i++)
    {
        if (i == now.tm_mday)
        {
            printk("\033[47;30;1m%.2d\033[0m ", i);
        }
        else
        {
            printk("%.2d ", i);
        }
        if ((i + tol_day + base_date().tm_wday - 1) % 7 == 6)
        {
            printk("\n");
        }
    }
    printk("\n");
}

int _clear(int argc, char *argv[])
{
    cls();
}

int _exit(int argc, char *argv[])
{
    processEnd();
}

/**
 * @description: Register command.
 */
void register_command(void)
{
    addNewCmd("help", "Usage: help [command]\nDisplay info about [command].", help);
    addNewCmd("cmd", "List available commands.", cmd);
    addNewCmd("history", "Usage: history [n]\nDisplay the history list.", history);
    addNewCmd("date", "Usage: date [FORMAT]\nDisplay the current time in the given FORMAT (Don't use spaces in FORMAT).", date);
    addNewCmd("cal", "Usage: cal [MONTH] [YEAR]\nDisplays the calendar.", cal);
    addNewCmd("echo", "Usage: echo [arg ...]\nWrite arguments to the standard output.", echo);
    addNewCmd("sleep", "Usage: sleep NUMBER\nPause for NUMBER seconds.", _sleep);
    addNewCmd("cls", "Usage: cls\nClear the screen.", _clear);
    addNewCmd("exit", "Usage: exit [status]\nExits the shell with a status code.", _exit);
}
